﻿using System;
using Platformer_Example.Controller.Character;
using Platformer_Example.Controller.Map;
using Transformable_Engine_v2.Engine;
using Transformable_Engine_v2.Engine.Helper;
using Transformable_Engine_v2.Engine.Transformable_Math.Geometry;

namespace Platformer_Example.Controller.Terrain
{
    public abstract class BaseStair : BaseTerrain
    {
        private readonly MapCellData.StairType _stairType;

        protected BaseStair(TE_Vector2 position, MapCellData.StairType type) : base(position)
        {
            _stairType = type;
            AddSprite(_stairType);
        }

        protected abstract void AddSprite(MapCellData.StairType type);

        protected override TerrainType GetTerrainType()
        {
            return TerrainType.Floor;
        }

        float CalculateDesiredPosition(float deltaX)
        {
            switch (_stairType)
            {
                case MapCellData.StairType.Stair11:
                    return CollisionArea.Y + Game.Options.GridSize - deltaX;
                case MapCellData.StairType.Stair11Desc:
                    return CollisionArea.Y + deltaX;
                case MapCellData.StairType.Stair21:
                    return CollisionArea.Y + Game.Options.GridSize - deltaX / 2;
                case MapCellData.StairType.Stair21Desc:
                    return CollisionArea.Y + deltaX / 2;
                case MapCellData.StairType.Stair31:
                    return CollisionArea.Y + Game.Options.GridSize - deltaX / 3;
                case MapCellData.StairType.Stair31Desc:
                    return CollisionArea.Y + deltaX / 3;
            }

            throw new Exception("Invalid stair type");
        }

        float GetPlayerPositionX(BaseGravityAffected character)
        {
            return character.GetAbsolutePosition().X - CollisionArea.Left;
        }

        public override bool IsTerrainCorrectlyLocated(TerrainType collisionType, BaseGravityAffected character)
        {
            return character.GetAbsolutePosition().Y <= CollisionArea.Bottom;
        }

        public override bool IsTerrainCollidingInOtherAxis(TerrainType collisionType, BaseGravityAffected character)
        {
            return GetPlayerPositionX(character).IsBetween(0, CollisionArea.Width);
        }

        public override float GetDistanceFromCharacter(TerrainType collisionType, BaseGravityAffected character)
        {
            float desiredPosition = CalculateDesiredPosition(GetPlayerPositionX(character));
            float currentPosition = character.GetAbsolutePosition().Y;

            if (currentPosition >= desiredPosition)
                return 0;
            else
            {
                return Math.Abs(desiredPosition - currentPosition);
            }
        }

        public override TerrainType ResolveCollision(BaseGravityAffected character, TerrainType collisionType, float movementOffset)
        {
            float desiredPosition = CalculateDesiredPosition(GetPlayerPositionX(character));
            character.MoveAbsolute(new TE_Vector2(character.GetAbsolutePosition().X, desiredPosition));

            return collisionType;
        }

        public override TE_Rectangle GetCollisionBox(TE_Vector2 size)
        {
            switch (_stairType)
            {
                case MapCellData.StairType.Stair11:
                case MapCellData.StairType.Stair11Desc:
                    return new TE_Rectangle(0, 0, 1, 2);
                case MapCellData.StairType.Stair21:
                case MapCellData.StairType.Stair21Desc:
                    return new TE_Rectangle(0, 0, 2, 2);
                case MapCellData.StairType.Stair31:
                case MapCellData.StairType.Stair31Desc:
                    return new TE_Rectangle(0, 0, 3, 2);
            }

            return null;
        }
    }
}